/* ** por compatibilidad se omiten tildes **
================================================================================
 TRABAJO PRACTICO 3 - System Programming - ORGANIZACION DE COMPUTADOR II - FCEN
================================================================================
  definicion de funciones del scheduler
*/

#include "screen.h"
#include "i386.h"
#include "tss.h"

static char* reloj[5];

static char puntos_rojo_ar[3];
static char puntos_azul_ar[3];

static int puntos_rojo = 0;
static int puntos_azul = 0;

unsigned char video_guardado[2*(CAMPO_SIZE_X+2)*(CAMPO_SIZE_Y+1)];

static char zombies_restantes_rojo_ar[3];
static char zombies_restantes_azul_ar[3];

static int zombies_restantes_rojo = 20;
static int zombies_restantes_azul = 20;

// este arreglo nos indica en qué estado se encuentra el reloj periodico 
// de cada tarea. '|' = 0, '/'= 1, '-' = 2, '\\'=3
static int reloj_tareas_rojo[CANT_ZOMBIS];
static int reloj_tareas_azul[CANT_ZOMBIS];

// nombres de los zombies
static char* nombre_zombies[CANT_ZOMBIS];

// esta función me sirve para traducir una posición a un offset
// de la memoria de video
unsigned int position_2_video(unsigned int y, unsigned int x) {
        return 2*(x + (CAMPO_SIZE_X+2)*y);
}

// funcion auxiliar para pintar un hexa
char value_to_hexa_char(unsigned int valor) {
	char retVal = '1';
	switch (valor) {
		case 0:
			return '0';
		case 1:
			return '1';
		case 2:
			return '2';
		case 3:
			return '3';
		case 4:
			return '4';
		case 5:
			return '5';
		case 6:
			return '6';
		case 7:
			return '7';
		case 8:
			return '8';
		case 9:
			return '9';
		case 10:
			return 'A';
		case 11:
			return 'B';
		case 12:
			return 'C';
		case 13:
			return 'D';
		case 14:
			return 'E';
		case 15:
			return 'F';

	}
	return retVal;
}


void borrar_posicion_zombi_jugador_rojo(int posicion_inicial_jugador_rojo ) {
 	print(" ", 0, posicion_inicial_jugador_rojo + 1, 0x44);
}

void borrar_posicion_zombi_jugador_azul(int posicion_inicial_jugador_azul) {
 	print(" ", 79, posicion_inicial_jugador_azul + 1, 0x11);
}

void pintar_posicion_zombi_jugador_rojo(int posicion_inicial_jugador_rojo, char * tipo_zombi_rojo) {
 	print(tipo_zombi_rojo, 0, posicion_inicial_jugador_rojo + 1, 0x4F);

}

void pintar_posicion_zombi_jugador_azul(int posicion_inicial_jugador_azul, char * tipo_zombi_azul) {
 	print(tipo_zombi_azul, 79, posicion_inicial_jugador_azul + 1, 0x1F);
}

void pintar_recorrido(int x, int y) {
 	print("x", x, y, 0x27);
}

void pintar_zombie_mapa_rojo(int x, int y, char * tipo_zombie) {
 	print(tipo_zombie, x, y, 0x4F);
}

void pintar_zombie_mapa_azul(int x, int y, char * tipo_zombie) {
 	print(tipo_zombie, x, y, 0x1F);
}

// funcion auxiliar para pintar un hexa
void imprimir_hexa_short(int x, int y, unsigned int valor, char color) {
	unsigned char* ptVideo = (unsigned char*) VIDEO;

	unsigned int valor_auxiliar = valor;
	valor_auxiliar <<= 28;
	valor_auxiliar >>= 28;
	*((unsigned char*) &ptVideo[position_2_video(y, x+3)]) = value_to_hexa_char(valor_auxiliar);
	*((unsigned char*) &ptVideo[position_2_video(y, x+3) + 1]) = color;
	valor_auxiliar = valor;
	valor_auxiliar <<= 24;
	valor_auxiliar >>= 28;
	*((unsigned char*) &ptVideo[position_2_video(y, x+2)]) = value_to_hexa_char(valor_auxiliar);
	*((unsigned char*) &ptVideo[position_2_video(y, x+2) + 1]) = color;
	valor_auxiliar = valor;
	valor_auxiliar <<= 20;
	valor_auxiliar >>= 28;
	*((unsigned char*) &ptVideo[position_2_video(y, x+1)]) = value_to_hexa_char(valor_auxiliar);
	*((unsigned char*) &ptVideo[position_2_video(y, x+1) + 1]) = color;
	valor_auxiliar = valor;
	valor_auxiliar <<= 16;
	valor_auxiliar >>= 28;
	*((unsigned char*) &ptVideo[position_2_video(y, x)]) = value_to_hexa_char(valor_auxiliar);
	*((unsigned char*) &ptVideo[position_2_video(y, x) + 1]) = color;

} 

void imprimir_hexa(int x, int y, unsigned int valor, char color) {
	unsigned char* ptVideo = (unsigned char*) VIDEO;

	unsigned int valor_auxiliar = valor;
	valor_auxiliar <<= 28;
	valor_auxiliar >>= 28;
	*((unsigned char*) &ptVideo[position_2_video(y, x+7)]) = value_to_hexa_char(valor_auxiliar);
	*((unsigned char*) &ptVideo[position_2_video(y, x+7) + 1]) = color;
	valor_auxiliar = valor;
	valor_auxiliar <<= 24;
	valor_auxiliar >>= 28;
	*((unsigned char*) &ptVideo[position_2_video(y, x+6)]) = value_to_hexa_char(valor_auxiliar);
	*((unsigned char*) &ptVideo[position_2_video(y, x+6) + 1]) = color;
	valor_auxiliar = valor;
	valor_auxiliar <<= 20;
	valor_auxiliar >>= 28;
	*((unsigned char*) &ptVideo[position_2_video(y, x+5)]) = value_to_hexa_char(valor_auxiliar);
	*((unsigned char*) &ptVideo[position_2_video(y, x+5) + 1]) = color;
	valor_auxiliar = valor;
	valor_auxiliar <<= 16;
	valor_auxiliar >>= 28;
	*((unsigned char*) &ptVideo[position_2_video(y, x+4)]) = value_to_hexa_char(valor_auxiliar);
	*((unsigned char*) &ptVideo[position_2_video(y, x+4) + 1]) = color;
	valor_auxiliar = valor;
	valor_auxiliar <<= 12;
	valor_auxiliar >>= 28;
	*((unsigned char*) &ptVideo[position_2_video(y, x+3)]) = value_to_hexa_char(valor_auxiliar);
	*((unsigned char*) &ptVideo[position_2_video(y, x+3) + 1]) = color;
	valor_auxiliar = valor;
	valor_auxiliar <<= 8;
	valor_auxiliar >>= 28;
	*((unsigned char*) &ptVideo[position_2_video(y, x+2)]) = value_to_hexa_char(valor_auxiliar);
	*((unsigned char*) &ptVideo[position_2_video(y, x+2) + 1]) = color;
	valor_auxiliar = valor;
	valor_auxiliar <<= 4;
	valor_auxiliar >>= 28;
	*((unsigned char*) &ptVideo[position_2_video(y, x+1)]) = value_to_hexa_char(valor_auxiliar);
	*((unsigned char*) &ptVideo[position_2_video(y, x+1) + 1]) = color;
	valor_auxiliar = valor;
	valor_auxiliar <<= 4;
	valor_auxiliar >>= 28;
	*((unsigned char*) &ptVideo[position_2_video(y, x)]) = value_to_hexa_char(valor_auxiliar);
	*((unsigned char*) &ptVideo[position_2_video(y, x) + 1]) = color;

} 


// guarda el screen
void guardar_screen() {

	unsigned char* ptVideo = (unsigned char*) VIDEO;
	int i;
	for (i = 0; i < 2*(CAMPO_SIZE_X+2)*(CAMPO_SIZE_Y+1); i++) {
			video_guardado[i] = ptVideo[i];
	}
}

void restaurar_screen() {
	unsigned char* ptVideo = (unsigned char*) VIDEO;
	int i;
	for (i = 0; i < 2*(CAMPO_SIZE_X+2)*(CAMPO_SIZE_Y+1); i++) {
			ptVideo[i] = video_guardado[i];
	}
}
// funcion auxiliar para imprimir texto
void imprimir_texto(char* texto, int x, int y,  unsigned int l_texto, char color) {
	int i = 0;
	char c;
	unsigned char* ptVideo = (unsigned char*) VIDEO;
	for (i = 0; i < l_texto; i++) {
		c = *(texto + i);
		*((unsigned char*) &ptVideo[position_2_video(y, x+i)]) = c;
		*((unsigned char*) &ptVideo[position_2_video(y, x+i)+1]) = color;
	}
}


// imprime el cuerpo del contexto (headers, etc).
void imprimir_cuerpo_contexto(char* encabezado, char* error, unsigned int l_encabezado, unsigned int l_error, char color) {
	int i = 0;
	int j = 0;
	char c = 0;
	unsigned char* ptVideo = (unsigned char*) VIDEO;
	*((unsigned char*) &ptVideo[position_2_video(5, 25)]) = 0;
	*((unsigned char*) &ptVideo[position_2_video(5, 25) + 1]) = 0x4F;


	for (i = 0; i < 31; i++) {
		*((unsigned char*) &ptVideo[position_2_video(4, 24+i)]) = 0;
		*((unsigned char*) &ptVideo[position_2_video(4, 24+i)+1]) = 0;
	}


	for (j = 5; j < 40; j++) {
		*((unsigned char*) &ptVideo[position_2_video(j, 24)]) = 0;
		*((unsigned char*) &ptVideo[position_2_video(j, 24)+1]) = 0;
		*((unsigned char*) &ptVideo[position_2_video(j, 54)]) = 0;
		*((unsigned char*) &ptVideo[position_2_video(j, 54)+1]) = 0;

	}

	for (; i < 28; i++) {
		c = *(encabezado + i);
		*((unsigned char*) &ptVideo[position_2_video(5, 26+i)]) = 0;
		*((unsigned char*) &ptVideo[position_2_video(5, 26+i)+1]) = 0x4F;
	}

	for (i = 6; i < 39; i++) {
		*((unsigned char*) &ptVideo[position_2_video(i, 24)]) = 0;
		*((unsigned char*) &ptVideo[position_2_video(i, 54)]) = 0;

		for (j = 25; j < 54; j++) {

			*((unsigned char*) &ptVideo[position_2_video(i, j)]) = 0;
			*((unsigned char*) &ptVideo[position_2_video(i, j)+1]) = 0x77;
		}
	}



	imprimir_texto("eax", 26, 7,  3, 0x70);
	imprimir_texto("cr0", 41, 7,  3, 0x70);
	imprimir_texto("ebx", 26, 9,  3, 0x70);
	imprimir_texto("cr2", 41, 9,  3, 0x70);
	imprimir_texto("ecx", 26, 11,  3, 0x70);
	imprimir_texto("cr3", 41, 11,  3, 0x70);
	imprimir_texto("edx", 26, 13,  3, 0x70);
	imprimir_texto("cr4", 41, 13,  3, 0x70);
	imprimir_texto("esi", 26, 15,  3, 0x70);
	imprimir_texto("esi", 26, 17,  3, 0x70);
	imprimir_texto("ebp", 26, 19,  3, 0x70);
	imprimir_texto("esp", 26, 21,  3, 0x70);
	imprimir_texto("eip", 26, 23,  3, 0x70);
	imprimir_texto("cs", 27, 25,  2, 0x70);
	imprimir_texto("stack", 41, 25,  5, 0x70);
	imprimir_texto("ds", 27, 27,  2, 0x70);
	imprimir_texto("es", 27, 29,  2, 0x70);
	imprimir_texto("fs", 27, 31,  2, 0x70);
	imprimir_texto("gs", 27, 33,  2, 0x70);
	imprimir_texto("ss", 27, 35,  2, 0x70);
	imprimir_texto("eflags", 27, 37,  6, 0x70);

	for (i = 0; i < 30; i++) {
		*((unsigned char*) &ptVideo[position_2_video(39, 24+i)]) = 0;
		*((unsigned char*) &ptVideo[position_2_video(39, 24+i)+1]) = 0;
	}

	for (i = 0; i < 29; i++) {
		if (i < l_encabezado) {

			c = *(encabezado + i);
			*((unsigned char*) &ptVideo[position_2_video(5, 25+i)]) = c;
			*((unsigned char*) &ptVideo[position_2_video(5, 25+i)+1]) = color;
		} else {
			*((unsigned char*) &ptVideo[position_2_video(5, 25+i)]) = 0;
			*((unsigned char*) &ptVideo[position_2_video(5, 25+i)+1]) = color;
		}
	}

	for (i = 0; i < 29; i++) {
		if (i < l_encabezado) {

			c = *(encabezado + i);
			*((unsigned char*) &ptVideo[position_2_video(5, 25+i)]) = c;
			*((unsigned char*) &ptVideo[position_2_video(5, 25+i)+1]) = color;
		} else {
			*((unsigned char*) &ptVideo[position_2_video(5, 25+i)]) = 0;
			*((unsigned char*) &ptVideo[position_2_video(5, 25+i)+1]) = color;
		}
	}

	for (i = 0; i < 29; i++) {
		if (i < l_error) {

			c = *(error + i);
			*((unsigned char*) &ptVideo[position_2_video(3, 25+i)]) = c;
			*((unsigned char*) &ptVideo[position_2_video(3, 25+i)+1]) = color;
		} else {
			*((unsigned char*) &ptVideo[position_2_video(3, 25+i)]) = 0;
			*((unsigned char*) &ptVideo[position_2_video(3, 25+i)+1]) = color;
		}
	}

}

void imprimir_contexto(tss tss, char * mensaje,  char* error, unsigned int l_mensaje, unsigned int l_error, unsigned int id_tarea, char color) {
	guardar_screen();

	imprimir_cuerpo_contexto(mensaje, error, l_mensaje, l_error, color);
	imprimir_hexa(30, 7, tss.eax, 0x7F);
	if (color == 0) {
		imprimir_hexa(45, 7,  get_cr0tarea_rojo(id_tarea), 0x7F);
	} else {
		imprimir_hexa(45, 7,  get_cr0tarea_azul(id_tarea), 0x7F);
	}
	imprimir_hexa(30, 9, tss.ebx, 0x7F);
	if (color == 0) {
		imprimir_hexa(45, 9,  get_cr2tarea_rojo(id_tarea), 0x7F);
	} else {
		imprimir_hexa(45, 9,  get_cr2tarea_azul(id_tarea), 0x7F);
	}
	imprimir_hexa(30, 11, tss.ecx, 0x7F);
	imprimir_hexa(45, 11, tss.cr3 , 0x7F);
	imprimir_hexa(30, 13, tss.edx, 0x7F);
	if (color == 0) {
		imprimir_hexa(45, 13,  get_cr4tarea_rojo(id_tarea), 0x7F);
	} else {
		imprimir_hexa(45, 13,  get_cr4tarea_azul(id_tarea), 0x7F);

	}
	imprimir_hexa(30, 15, tss.esi, 0x7F);
	imprimir_hexa(30, 17, tss.edi, 0x7F);
	imprimir_hexa(30, 19, tss.ebp, 0x7F);
	imprimir_hexa(30, 21, tss.esp, 0x7F);
	imprimir_hexa(30, 23, tss.eip, 0x7F);
	imprimir_hexa_short(30, 25, tss.cs, 0x7F);
	imprimir_hexa_short(30, 27, tss.ds, 0x7F);
	imprimir_hexa_short(30, 29, tss.es, 0x7F);
	imprimir_hexa_short(30, 31, tss.fs, 0x7F);
	imprimir_hexa_short(30, 33, tss.gs, 0x7F);
	imprimir_hexa_short(30, 35, tss.ss, 0x7F);
	imprimir_hexa(34, 37, tss.eflags, 0x7F);
	unsigned int esp_ = tss.esp;
	int i = 0;
	// imprimo el stack
	for (i = 0; i < 6; i++) {
			imprimir_hexa(41, 27+i, *((unsigned int*) esp_), 0x7F);
			esp_ +=4;
			if (esp_ == tss.ebp)
			    break;
	}	
	
}
void inicializar_datos_pantalla() {
	reloj[0] = "|";
	reloj[1] = "\\";
	reloj[2] = "-";
	reloj[3] = "/"; 
	reloj[4] = "x"; 
 
	int i = 0;

	// inicializo los relojes de los zombies
	for (i = 0; i < CANT_ZOMBIS; i++) {
	   reloj_tareas_rojo[i] = 4; // inicializo los slots como vacíos para el jugador rojo
	   reloj_tareas_azul[i] = 4; // inicializo los slots como vacíos para el jugador azul
	}	
	nombre_zombies[0] = "1";
	nombre_zombies[1] = "2";
	nombre_zombies[2] = "3";
	nombre_zombies[3] = "4";
	nombre_zombies[4] = "5";
	nombre_zombies[5] = "6";
	nombre_zombies[6] = "7";
	nombre_zombies[7] = "8";

}

void imprimir_zombi_destruido(int x, int y, int color) {
	if (color == 0) {
		print("x", x, y, 0x24);
	} else {
		print("x", x, y, 0x21);

	}
}

void convertir_a_string (unsigned int numero, char arreglo[2]) {
	if (numero == 20) {
	    arreglo[0] = 50;
	    arreglo[1] = 48;
	} else if (numero < 10) {
		arreglo[0] = 48;
		arreglo[1] = 48 + numero; 
	} else {
		arreglo[0] = 49;
		arreglo[1] = 38 + numero;
	}

	arreglo[2] = 0;

	
}

void convertir_a_string_sin_decenas (unsigned int numero, char arreglo[2]) {
	if (numero < 10) {
		arreglo[0] = 32;
		arreglo[1] = 48 + numero; 
	} else {
		if (numero >= 20) {
		   arreglo[0] = 50;
		   arreglo[1] = 28 + numero;
		} else  if (numero >= 30) {
		   arreglo[0] = 51;
		   arreglo[1] = 18 + numero;		
		} else if (numero == 40) {
		    arreglo[0] = 52;
		   arreglo[1] = 31;		
		} else{
			arreglo[0] = 49;
			arreglo[1] = 38 + numero;
		}
	}
	arreglo[2] = 0;
	
}

void aumentar_puntos_rojo() {
	puntos_rojo++;
	imprimir_puntos_rojo();
}

void aumentar_puntos_azul() {
	puntos_azul++;
	imprimir_puntos_azul();
}

void imprimir_puntos_rojo() {
	convertir_a_string_sin_decenas(puntos_rojo, puntos_rojo_ar);
 	print((char *) &puntos_rojo_ar, OFFSET_PUNTOS_X_ROJO, OFFSET_PUNTOS_Y_ROJO, 0x4F);
}

void imprimir_puntos_azul() {
	convertir_a_string_sin_decenas(puntos_azul, puntos_azul_ar);
 	print((char *) &puntos_azul_ar, OFFSET_PUNTOS_X_AZUL, OFFSET_PUNTOS_Y_AZUL, 0x1F);

}


unsigned int dame_restantes_rojo() {
	return zombies_restantes_rojo;
}

// imprime el contexto de la tarea id en la pantalla
void imprimir_contexto_game(unsigned int zombi, unsigned int color, char * encabezado, char * mensaje_excepcion, unsigned int length) {
	if (color == 0) {
		imprimir_contexto(get_tss(zombi, color), encabezado,  mensaje_excepcion, 18,  length, zombi, 0x4F);
	} else {
		imprimir_contexto(get_tss(zombi, color), encabezado,  mensaje_excepcion, 18,  length, zombi, 0x1F);
	}
}

unsigned int dame_restantes_azul() {
	return zombies_restantes_azul;
}
void reducir_restantes_rojo() {
	zombies_restantes_rojo--;
	imprimir_restantes_rojo();
}

void reducir_restantes_azul() {
	zombies_restantes_azul--;
	imprimir_restantes_azul();
}

void imprimir_restantes_rojo() {
	convertir_a_string(zombies_restantes_rojo, zombies_restantes_rojo_ar);
 	print((char *) &zombies_restantes_rojo_ar, OFFSET_ZOMBIES_RESTANTES_X_ROJO, OFFSET_ZOMBIES_RESTANTES_Y_ROJO, 0x4F);
}

void imprimir_restantes_azul() {
	convertir_a_string(zombies_restantes_azul, zombies_restantes_azul_ar);
 	print((char *) &zombies_restantes_azul_ar, OFFSET_ZOMBIES_RESTANTES_X_AZUL, OFFSET_ZOMBIES_RESTANTES_Y_AZUL, 0x1F);

}

void disable_reloj_zombie_rojo(int nZombie) {
	reloj_tareas_rojo[nZombie] = 4;
}

void disable_reloj_zombie_azul(int nZombie) {
	reloj_tareas_azul[nZombie] = 4;
}

void avanzar_reloj_zombie_rojo(int nZombie) {
	reloj_tareas_rojo[nZombie]++;
	if (reloj_tareas_rojo[nZombie] > 3)
		reloj_tareas_rojo[nZombie] = 0;
}

void avanzar_reloj_zombie_azul(int nZombie) {
	reloj_tareas_azul[nZombie]++;
	if (reloj_tareas_azul[nZombie] > 3)
		reloj_tareas_azul[nZombie] = 0;
}

void imprimir_reloj_zombie_rojo(int nZombie) {
	char atributos = 0x0F;
	print(nombre_zombies[nZombie], OFFSET_RELOJ_X_ROJO + nZombie*2, OFFSET_RELOJ_Y, atributos);



	if (reloj_tareas_rojo[nZombie] == 4)
		atributos = 0x04;

	print(reloj[reloj_tareas_rojo[nZombie]], OFFSET_RELOJ_X_ROJO + nZombie*2, OFFSET_RELOJ_Y + 2, atributos);
}

void imprimir_reloj_zombie_azul(int nZombie) {
	
	char atributos = 0x0F; 
	print(nombre_zombies[nZombie], OFFSET_RELOJ_X_AZUL + nZombie*2, OFFSET_RELOJ_Y, atributos);


	if (reloj_tareas_azul[nZombie] == 4)
		atributos = 0x01;

	print(reloj[reloj_tareas_azul[nZombie]], OFFSET_RELOJ_X_AZUL + nZombie*2, OFFSET_RELOJ_Y + 2, atributos);
}

void imprimir_todos_los_relojes_zombies() {
	int i = 0;

	for (i = 0; i < CANT_ZOMBIS; i++) {
		imprimir_reloj_zombie_rojo(i);
		imprimir_reloj_zombie_azul(i);
	}
}


void print(const char * text, unsigned int x, unsigned int y, unsigned short attr) {
    ca (*p)[VIDEO_COLS] = (ca (*)[VIDEO_COLS]) VIDEO;
    int i;
    for (i = 0; text[i] != 0; i++) {
        p[y][x].c = (unsigned char) text[i];
        p[y][x].a = (unsigned char) attr;
        x++;
        if (x == VIDEO_COLS) {
            x = 0;
            y++;
        }
    }
}

void print_hex(unsigned int numero, int size, unsigned int x, unsigned int y, unsigned short attr) {
    ca (*p)[VIDEO_COLS] = (ca (*)[VIDEO_COLS]) VIDEO; // magia
    int i;
    char hexa[8];
    char letras[16] = "0123456789ABCDEF";
    hexa[0] = letras[ ( numero & 0x0000000F ) >> 0  ];
    hexa[1] = letras[ ( numero & 0x000000F0 ) >> 4  ];
    hexa[2] = letras[ ( numero & 0x00000F00 ) >> 8  ];
    hexa[3] = letras[ ( numero & 0x0000F000 ) >> 12 ];
    hexa[4] = letras[ ( numero & 0x000F0000 ) >> 16 ];
    hexa[5] = letras[ ( numero & 0x00F00000 ) >> 20 ];
    hexa[6] = letras[ ( numero & 0x0F000000 ) >> 24 ];
    hexa[7] = letras[ ( numero & 0xF0000000 ) >> 28 ];
    for(i = 0; i < size; i++) {
        p[y][x + size - i - 1].c = hexa[i];
        p[y][x + size - i - 1].a = attr;
    }
}





